package com.redepronik.negosys.invfac.service;

import static com.redepronik.negosys.utils.Utils.presentaMensaje;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.faces.application.FacesMessage;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.redepronik.negosys.invfac.dao.GrupoDao;
import com.redepronik.negosys.invfac.dao.ProductoDao;
import com.redepronik.negosys.invfac.entity.Caracteristica;
import com.redepronik.negosys.invfac.entity.Grupo;
import com.redepronik.negosys.invfac.entity.Grupocaracteristica;
import com.redepronik.negosys.invfac.entity.Producto;
import com.redepronik.negosys.invfac.entity.Productocaracteristica;

@Service
public class GrupoServiceImpl implements GrupoService {

	@Autowired
	private GrupoDao grupoDao;

	@Autowired
	private ProductoDao productoDao;

	@Autowired
	private CaracteristicaService caracteristicaService;

	private ValidatorFactory factory = Validation
			.buildDefaultValidatorFactory();
	private Validator validator = factory.getValidator();

	public void actualizar(Grupo grupo) {
		Set<ConstraintViolation<Grupo>> violations = validator.validate(grupo);
		if (violations.size() > 0)
			for (ConstraintViolation<Grupo> cv : violations)
				presentaMensaje(FacesMessage.SEVERITY_INFO, cv.getMessage());
		else if (grupoCaracteristica(grupo)) {
		} else if (grupoDao.comprobarIndices(Grupo.class, "nombre",
				grupo.getNombre(), String.valueOf(grupo.getGrupoid())))
			presentaMensaje(FacesMessage.SEVERITY_ERROR,
					"EL GRUPO: " + grupo.getNombre() + " YA EXISTE", "error",
					false);
		else {
			boolean bd;
			int[] bandera = null;
			if (grupo.getProductos() != null)
				for (Producto p : grupo.getProductos()) {
					bandera = p.getProductocaracteristicas() != null ? new int[p
							.getProductocaracteristicas().size()] : new int[0];

					if (grupo.getGrupocaracteristicas() != null)
						for (Grupocaracteristica gc : grupo
								.getGrupocaracteristicas()) {
							bd = false;
							for (Productocaracteristica pc : p
									.getProductocaracteristicas())
								if (gc.getCaracteristica()
										.getCaracteristicaid() == pc
										.getCaracteristica()
										.getCaracteristicaid()) {
									pc.setOrden(gc.getOrden());
									pc.setImprimir(gc.getImprimir());
									bandera[p.getProductocaracteristicas()
											.indexOf(pc)] = 1;
									bd = true;
									break;
								}

							if (!bd) {
								Productocaracteristica pc = new Productocaracteristica();
								pc.setCaracteristica(gc.getCaracteristica());
								pc.setImprimir(gc.getImprimir());
								pc.setOrden(gc.getOrden());
								p.addProductocaracteristica(pc);
							}
						}

					if (p.getProductocaracteristicas() != null)
						for (int i = 0; i < bandera.length; i++)
							if (bandera[i] == 0)
								p.getProductocaracteristicas().remove(i);

					productoDao.actualizar(p);
				}
			grupoDao.actualizar(grupo);
			presentaMensaje(FacesMessage.SEVERITY_INFO, "MODIFICO EL GRUPO: "
					+ grupo.getNombre(), "error", true);
		}
	}

	private boolean grupoCaracteristica(Grupo grupo) {
		int size = grupo.getGrupocaracteristicas().size() - 1;
		if (grupo.getGrupocaracteristicas().get(size).getCaracteristica() == null)
			grupo.getGrupocaracteristicas().remove(size);
		for (Grupocaracteristica gc : grupo.getGrupocaracteristicas())
			if (gc.getImprimir())
				return false;
		presentaMensaje(FacesMessage.SEVERITY_INFO,
				"TIENE QUE TENER UNA CARACTERISTICA COMO IMPRIMIR SI");
		return true;
	}

	public void comprobarCaracteristica(int fila, Grupo grupo,
			Caracteristica caracteristica) {
		caracteristica = caracteristicaService.obtenerPorId(caracteristica
				.getCaracteristicaid());
		boolean bn = false;
		for (int i = 0; i < grupo.getGrupocaracteristicas().size() - 1; i++) {
			if (i != fila
					&& grupo.getGrupocaracteristicas().get(i)
							.getCaracteristica().getCaracteristicaid() == caracteristica
							.getCaracteristicaid()) {
				bn = true;
				break;
			}
		}
		if (bn)
			presentaMensaje(FacesMessage.SEVERITY_INFO, "LA CARACTERISTICA: "
					+ caracteristica.getNombre() + " YA EXISTE");
		else
			grupo.getGrupocaracteristicas().get(fila)
					.setCaracteristica(caracteristica);
		caracteristica = new Caracteristica();
	}

	public void añadirFilaCaracteristica(Grupo grupo) {
		if (grupo.getGrupocaracteristicas() == null
				|| grupo.getGrupocaracteristicas().isEmpty()) {
			grupo.setGrupocaracteristicas(new ArrayList<Grupocaracteristica>());
			Grupocaracteristica grupoCaracteristica = new Grupocaracteristica();
			grupoCaracteristica.setOrden(1);
			grupoCaracteristica.setCaracteristica(caracteristicaService
					.obtenerPorId(1));
			grupoCaracteristica.setImprimir(true);
			grupo.addGrupocaracteristica(grupoCaracteristica);
			grupoCaracteristica = new Grupocaracteristica();
			grupoCaracteristica.setOrden(2);
			grupoCaracteristica.setCaracteristica(caracteristicaService
					.obtenerPorId(2));
			grupoCaracteristica.setImprimir(true);
			grupo.addGrupocaracteristica(grupoCaracteristica);
			añadirFilaCaracteristica(grupo);
		} else {
			int size = grupo.getGrupocaracteristicas().size() - 1;
			if (grupo.getGrupocaracteristicas().get(size).getCaracteristica() != null) {
				Grupocaracteristica grupoCaracteristica = new Grupocaracteristica();
				grupoCaracteristica.setOrden(size + 2);
				grupoCaracteristica.setImprimir(true);
				grupo.addGrupocaracteristica(grupoCaracteristica);
			} else
				presentaMensaje(FacesMessage.SEVERITY_INFO,
						"YA TIENE UNA FILA AGREGADA");
		}
	}

	public void eliminar(Grupo grupo) {
		grupo.setActivo(grupo.getActivo() ? false : true);
		grupoDao.actualizar(grupo);
		presentaMensaje(FacesMessage.SEVERITY_INFO,
				(grupo.getActivo() ? "ACTIVO " : "DESACTIVO ") + "EL GRUPO: "
						+ grupo.getNombre());
	}

	public void eliminarCaracteristica(Grupo grupo,
			Grupocaracteristica grupoCaracteristica) {
		if (grupo.getGrupocaracteristicas().size() > 1) {
			String caracteristica = grupoCaracteristica.getCaracteristica() != null ? grupoCaracteristica
					.getCaracteristica().getNombre() : "VACIA";
			grupo.getGrupocaracteristicas().remove(grupoCaracteristica);
			int idx = 1;
			for (Grupocaracteristica gc : grupo.getGrupocaracteristicas())
				gc.setOrden(idx++);
			presentaMensaje(FacesMessage.SEVERITY_INFO,
					"SE ELIMINO LA CARACTERISTICA " + caracteristica);
		} else
			presentaMensaje(FacesMessage.SEVERITY_INFO,
					"DEBE TENER AL MENOS UNA CARACTERISTICA VÁLIDA");
	}

	public List<Grupo> insertar(Grupo grupo) {
		grupo.setActivo(true);
		Set<ConstraintViolation<Grupo>> violations = validator.validate(grupo);
		if (violations.size() > 0)
			for (ConstraintViolation<Grupo> cv : violations)
				presentaMensaje(FacesMessage.SEVERITY_INFO, cv.getMessage());
		else if (grupoCaracteristica(grupo)) {
		} else if (grupoDao.comprobarIndices(Grupo.class, "nombre",
				grupo.getNombre(), String.valueOf(grupo.getGrupoid())))
			presentaMensaje(FacesMessage.SEVERITY_ERROR,
					"EL GRUPO: " + grupo.getNombre() + " YA EXISTE", "error",
					true);
		else {
			grupoDao.insertar(grupo);
			presentaMensaje(FacesMessage.SEVERITY_INFO, "INSERTO EL GRUPO: "
					+ grupo.getNombre(), "error", true);
		}
		return obtener();
	}

	public List<Grupo> obtener() {
		List<Grupo> lista = grupoDao.obtenerPorHql(
				"select g from Grupo g where g.activo=true order by g.nombre",
				new Object[] {});
		return lista;
	}

	public List<Grupo> obtener(Boolean activo) {
		List<Grupo> lista = grupoDao.obtenerPorHql(
				"select distinct g from Grupo g "
						+ "left join fetch g.productos p "
						+ "left join fetch p.productocaracteristicas pc "
						+ "left join fetch p.productounidads pu "
						+ "left join fetch p.tipoPrecioProductos tpp "
						+ "left join fetch g.grupocaracteristicas gc "
						+ "where g.activo=true order by g.nombre",
				new Object[] {});
		return lista;
	}

	public Grupo obtenerPorGrupoId(Integer grupoId) {
		Grupo grupo = grupoDao
				.obtenerPorHql(
						"select g from Grupo g inner join fetch g.grupocaracteristicas gc where g.activo=true and g.grupoid=?1 order by gc.orden",
						new Object[] { grupoId }).get(0);
		return grupo;
	}

	public List<Grupo> obtenerProductosGrupo() {
		List<Grupo> lista = grupoDao.obtenerPorHql(
				"select distinct g from Grupo g "
						+ "left join fetch g.productos p "
						+ "where g.activo=true order by g.nombre",
				new Object[] {});
		return lista;
	}
}